/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../impl/head.h"
#include "callback_impl.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 

namespace xos_box
{

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static callback_impl::ITEM_DATA xos_item_data;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    callback_impl::callback_impl() : m_num(0)
    {
        init_data();
    }

    callback_impl::~callback_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int callback_impl::get_xos_item_data( ITEM_DATA*& item_ptr )
    {
        int ret = 0;
        xos_item_data.set_container( mgr::container() );
        item_ptr = &xos_item_data;
        return ret;
    }

    int callback_impl::init()
    {
        int nRet = 0;

        if( 0 == nRet )
        {
            m_pEvent = mgr::container()->xos()->event();
        }

        if( 0 == nRet )
        {
            m_pQueue = mgr::get()->queue();
        }

        if( 0 == nRet )
        {
            m_pThread = mgr::container()->xos()->thread();
            nRet = m_pThread->create( thread, this );
        }

        return nRet;
    }

    int callback_impl::term()
    {
        int nRet = 0;

        if( m_pThread && m_pEvent )
        {
            m_bQuit = true;
            m_pEvent->set_event();
            m_pThread->wait();
            m_pThread->release();
            m_pThread = 0;
        }

        xos_stl::release_interface( m_pQueue );
        xos_stl::release_interface( m_pEvent );

        init_data();

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    void * callback_impl::thread( void * lpData )
    {
        callback_impl & obj = *( callback_impl * )lpData;

        while( !obj.m_bQuit )
        {
            obj.m_pEvent->wait( xos::i_event::EVENT_WAIT_INFINITE );
            obj.run();
        }

        return 0;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int callback_impl::init_data()
    {
        int ret = 0;
        m_num.store( 0, std::memory_order_relaxed );
        m_bQuit = false;
        m_pThread = 0;
        m_pEvent = 0;
        m_pQueue = 0;
        return ret;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int callback_impl::run()
    {
        int nRet = 0;

        bool bFinished = false;

        while( !bFinished )
        {
            xos::f_runnable f_run = 0;
            i_msg * pMsg = 0;

            pMsg = (i_msg*)m_pQueue->pop_front();
            if( pMsg )
            {
                m_num.fetch_sub( 1, std::memory_order_relaxed );
                f_run = pMsg->get_runnable( 0, 0 );
            }
            else
            {
                bFinished = true;
            }

            if( f_run )
            {
                f_run( pMsg );
            }
        }

        return nRet;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int callback_impl::notify( i_msg *& p )
    {
        int nRet = 0;

        m_pQueue->push_back( p );
        m_num.fetch_add( 1, std::memory_order_relaxed );
        m_pEvent->set_event();
        p = 0;

        return nRet;
    }

    int callback_impl::size()
    {
        int ret = 0;

        ret = m_num.load( std::memory_order_acquire );

        return ret;
    }

} // xos
